Part 0: Clean the data

Step 1. load the libraries

library(tm)
library(plyr)
library(dplyr)
library(ggplot2)
library(tidyr)
library(readr)
library(stringr)
library(scales)
library(tidytext)
library(textdata)
library(ngram)
library(forcats)
library(syuzhet)
library(wordcloud)
library(reshape2)
library(topicmodels)

library(DT)

library(gridExtra)

Step 2: Process the data

# This data is processed from Text_Pre-processing file
hm_data <- read_csv("../data/output/processed_moments.csv")

urlfile<-'https://raw.githubusercontent.com/rit-public/HappyDB/master/happydb/data/demographic.csv'
demo_data <- read_csv(urlfile)

names(hm_data)
 [1] "hmid"                  "wid"                   "reflection_period"     "original_hm"          
 [5] "cleaned_hm"            "modified"              "num_sentence"          "ground_truth_category"
 [9] "predicted_category"    "id"                    "text"                 
## Select the data
happydb <- hm_data %>%
  inner_join(demo_data, by = "wid") %>%
  select(gender, 
         reflection_period,
         text)

# Merge the text data with demographic data into a CSV file
# write_csv(happydb, "../data/output/happydb.csv")
happydb = read.csv("../data/output/happydb.csv")

Part 1: What’s the difference of the words in each gender group?

In order to analyze the components of the text in each group, the barplot and wordcloud are used. #### Step 1 : Filter data

female <- happydb %>%
  filter(gender == 'f')
male <- happydb %>%
  filter(gender == 'm')

urlfile<-'https://raw.githubusercontent.com/rit-public/HappyDB/master/happydb/data/senselabel.csv'
sense_data <- read.csv(urlfile, stringsAsFactors = F)
data("stop_words")

word <- c("happy","ago","yesterday","lot","today","months","month",
                 "happier","happiest","last","week","past","day")

stop_words <- stop_words %>%
  bind_rows(mutate(tibble(word), lexicon = "updated"))

# females' answer word cleaning
female_text <- female$text %>% as.vector()  %>% 
  tibble(text = .) %>% 
  unnest_tokens(word, text) %>% 
  anti_join(stop_words)
Joining, by = "word"
# males' answer word cleaning
male_text <- male$text %>% as.vector()  %>% 
  tibble(text = .) %>% 
  unnest_tokens(word, text) %>% 
  anti_join(stop_words)
Joining, by = "word"

Step 2: Word Frequency

  • Each gender’s word frequency
freq_f <- female_text %>% count(word, sort = TRUE) # count frequency and sort by descending order
freq_m <- male_text %>% count(word, sort = TRUE) # count frequency and sort by descending order

# visualize the frequency
freq_f %>%
  filter(n > 1500) %>%
  mutate(word = reorder(word, n)) %>%
  ggplot(aes(word, n)) +
  geom_col(fill = "pink") +
  xlab(NULL) +
  ggtitle("Female word frequency")+
  coord_flip()


freq_m %>%
  filter(n > 1500) %>%
  mutate(word = reorder(word, n)) %>%
  ggplot(aes(word, n)) +
  geom_col(fill= "skyblue") +
  xlab(NULL) +
  ggtitle("Male word frequency")+
  coord_flip()

  • Combination of gender word frequency
# join each gender's word frequency 
frequency <- bind_rows(mutate(freq_f, gender = "Female"),
                       mutate(freq_m, gender = "Male")) %>%
   mutate(word = str_extract(word, "[a-z']+")) %>%
   count(gender, word) %>%
   group_by(gender) %>%
   mutate(proportion = n / sum(n)) %>%
   select(-n) %>%  # delete n var
   spread(gender, proportion) %>%  # word female male as columns
   gather(gender, proportion, `Male`) %>% drop_na()
ggplot(frequency, aes(x = proportion, y = `Female`, color = abs(`Female` - proportion))) +
  geom_abline(color = "gray40", lty = 2) +
  geom_jitter(alpha = 0.1, size = 2.5, width = 0.3, height = 0.3) +
  geom_text(aes(label = word), check_overlap = TRUE, vjust = 1.5) +
  scale_x_log10(labels = percent_format()) +
  scale_y_log10(labels = percent_format()) +
  scale_color_gradient(limits = c(0, 0.001), low = "darkslategray4", high = "gray75") +
  facet_wrap(~gender, ncol = 2) +
  theme(legend.position="none") +
  labs(y = "Female", x = NULL)

Words that are close to the line in these plots have similar frequencies in both sets of texts, which means there is huge similarity between females’ response and males’ response

  • Combine with position
# combine with position 
pos <- sense_data %>%
  select(lowercaseLemma, POS) %>% 
  rename(word = lowercaseLemma)  %>% 
  unique()

pos_f <- freq_f %>% inner_join(pos) %>% 
  group_by(POS) %>% 
  summarise(n = sum(n)) %>% 
  mutate(proportion = n /sum(n))
Joining, by = "word"
pos_m  <- freq_m %>% inner_join(pos)  %>% 
  group_by(POS) %>% 
  summarise(n= sum(n)) %>% 
  mutate(proportion = n /sum(n))
Joining, by = "word"
pos_f %>%
  mutate(POS = reorder(POS, proportion)) %>%
  ggplot(aes(POS, proportion)) +
  geom_col(fill = "pink") +
  xlab(NULL) +
  ggtitle("Female Part of Speech Proportion")+
  coord_flip()


pos_m %>%
  mutate(POS = reorder(POS, proportion)) %>%
  ggplot(aes(POS, proportion)) +
  geom_col(fill = "skyblue") +
  xlab(NULL) +
  ggtitle("Male Part of Speech Proportion")+
  coord_flip()

  • WordCloud of text word
### General Word Cloud

# palatte
colorVec_f = rep(c('red', 'lightpink'), length.out=nrow(freq_f))

freq_f %>% with(wordcloud(word, n, max.words = 100, colors =colorVec_f))


# palatte
colorVec_m = rep(c('blue', 'skyblue'), length.out=nrow(freq_m))

freq_m %>% with(wordcloud(word, n, max.words = 100, colors =colorVec_m))

Summary

The barplots show that both male and female like use nouns, verbs and adjs to express the happy moments. The top 10 words of frequency in each groups also support the notation. Women have 8 nouns and 2 verbs and man have 7 nouns, 2 verbs and 1 adverb(finally).

In the barplot and wordcloud graphs of both female and male, we can find that both women and men are enjoyed the happy moments with their friends. But women tend to be more bond with people around them for the words like husband, daughter, son, family come up more frequently than men’s.

Part 2: What’s the difference of the periods in each gender group?

For the infomation of the difference in the numbers and contents of periods in each gender group, I’m gonna use the number count, word cloud and ks-test.

Step 1. Numbers of reflection

ggplot(happydb,aes(x = happydb$gender,fill = happydb$reflection_period))+
  geom_bar(position = "fill") +
  labs(title = 'Reflection Period of Different Gender', x = 'Gender')

Step 2. Filtering

Step 3. Period difference within gender group

  • Preprocessing
fre
Error: object 'fre' not found
  • Word Cloud
word_f <- bind_rows(mutate(freq_f24h, time = "24h"),
                       mutate(freq_f3m, time = "3m"))

word_m <- bind_rows(mutate(freq_m24h, time = "24h"),
                       mutate(freq_m3m, time = "3m"))
word_f %>%
  acast(word ~ time, value.var = "n", fill = 0) %>%
  comparison.cloud(colors = c("grey20", "pink"),
                   max.words = 100)

word_m %>%
  acast(word ~ time, value.var = "n", fill = 0) %>%
  comparison.cloud(colors = c("grey20", "skyblue"),
                   max.words = 100)
  • KS test
ks.test(pos_f24h$proportion, pos_f3m$proportion)
ks.test(pos_m24h$proportion, pos_m3m$proportion)

There is no difference between the part of speech chosen in the 3 month or 24 hour within each gender group.

Step 4. Period difference between gender group

  • Preprocessing
h24 <- bind_rows(mutate(pos_f24h, gender = "female"),
                       mutate(pos_m24h, gender = "male"))
m3 <- bind_rows(mutate(pos_f3m, gender = "female"),
                       mutate(pos_m3m, gender = "male"))

h24 %>%
  group_by(gender) %>%
  ungroup() %>%
  mutate(POS = reorder(POS, n)) %>%
  ggplot(aes(POS, n, fill = gender)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~gender,scales = "free_y") +
  labs(y = "Contribution to Part Of Speech",
       x = NULL, title = "24 hour") +
  coord_flip()

m3 %>%
  group_by(gender) %>%
  ungroup() %>%
  mutate(POS = reorder(POS, n)) %>%
  ggplot(aes(POS, n, fill = gender)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~gender,scales = "free_y") +
  labs(y = "Contribution to Part Of Speech",
       x = NULL , title = "3 month") +
  coord_flip()
  • Word Cloud

  • KS test
#use the ks.test
ks.test(pos_f24h$proportion,pos_m24h$proportion);ks.test(pos_f3m$proportion,pos_m3m$proportion)
#### Step 5. Topic Modeling

Summary

For both female and male, there is no difference in the total number of the reflection period. But with the content of each period, female and male show differently.

Since the p-values of Kolmogorov-Smirnov test are very close to 1, the null hypothesis cannot be rejected at 0.01 significance which means there is no statistically difference between the POS of 24 hours and that of 3 months in each gender group.

After removing the most frequently used words in each group, the results show that in 24-hour’s memory, women have more ‘fleeting’ words - words describing movement, such as watched, feel, enjoy, ect. In 3-month’s memory, women have more nouns describing the person they shared the happy moments with. This is compatible with the memory loss. But focusing on men’s words in different reflection period, the POS of the words seem remain.

Part 3: Sentiment Analysis

Step 1. data process

# obtained sentiment
bing = get_sentiments("bing")

female_sentiment <- female_text %>% inner_join(bing) %>%
  count(word, sentiment, sort = TRUE) %>%
  ungroup()

male_sentiment <- male_text %>% inner_join(bing) %>%
  count(word, sentiment, sort = TRUE) %>%
  ungroup()

Step 2. bar plot

female_sentiment %>%
  group_by(sentiment) %>%
  top_n(10) %>%
  ungroup() %>%
  mutate(word = reorder(word, n)) %>%
  ggplot(aes(word, n, fill = sentiment)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~sentiment, scales = "free_y") +
  labs(y = "Contribution to sentiment",
       x = NULL) +
  coord_flip()


male_sentiment %>%
  group_by(sentiment) %>%
  top_n(10) %>%
  ungroup() %>%
  mutate(word = reorder(word, n)) %>%
  ggplot(aes(word, n, fill = sentiment)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~sentiment, scales = "free_y") +
  labs(y = "Contribution to sentiment",
       x = NULL) +
  coord_flip()

The top 10 words in positive and negative aspect don’t differ from each gender, just the order changed.

Step 3s. word cloud

female_text %>%
  inner_join(bing) %>%
  count(word, sentiment, sort = TRUE) %>%
  acast(word ~ sentiment, value.var = "n", fill = 0) %>%
  comparison.cloud(colors = c("grey20", "pink"),
                   max.words = 100)


male_text %>%
  inner_join(bing) %>%
  count(word, sentiment, sort = TRUE) %>%
  acast(word ~ sentiment, value.var = "n", fill = 0) %>%
  comparison.cloud(colors = c("gray20", "skyblue"),
                   max.words = 100)

Step 4. KS test

Here we use the nrc sentiment

nrc = get_sentiments("nrc")

nrc_f <-  female_text %>%
  inner_join(nrc) %>%
  count(word,sentiment) %>%
  spread(sentiment, n, fill = 0) %>%
  select(-word) %>% 
  as.matrix() %>% 
  apply(2,sum)

nrc_m <- male_text %>%
  inner_join(nrc) %>%
  count(word,sentiment) %>%
  spread(sentiment, n, fill = 0) %>%
  select(-word) %>% 
  as.matrix() %>% 
  apply(2,sum)

#ks.test of sentiment values of each group
ks.test(nrc_f, nrc_m)

Summary

Both female and male use more positive words than negative words to express their happy moments. For the sense of words, the words which show joy and anticipation are more likely used for happy moments. The histogram shows both mean of the sentiment values are concerntrated on 0. Under the ks.test, there is no significantly difference between the sense used by women and that by man.

Part 4: Conclusion

From the analysis above, we can firstly know that the happy moments are mostly postive which is confirmed with the name of the research ‘Happy Moments’. Both women and men used nouns, verbs and adjectives to express their happy moments. Besides, women like to remember the people who spent the happy moments with them but men don’t show the tendency.

There is no statistically difference between the numbers of happy moments of different period in each gender group.But the content of the word used by females and males show difference. Women tends to use verbs or adjectives to describe their happy moment in short-term memories, more nouns for discription in longer-term memories while men don’t show the same tendency.

LS0tCnRpdGxlOiAiUHJvamVjdCAxIgphdXRob3I6ICdaaXlpIExpYW8gJwpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKLS0tCgojIyBQYXJ0IDA6IENsZWFuIHRoZSBkYXRhCiMjIyMgU3RlcCAxLiBsb2FkIHRoZSBsaWJyYXJpZXMgCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRtKQpsaWJyYXJ5KHBseXIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeSh0aWR5cikKbGlicmFyeShyZWFkcikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeSh0aWR5dGV4dCkKbGlicmFyeSh0ZXh0ZGF0YSkKbGlicmFyeShuZ3JhbSkKbGlicmFyeShmb3JjYXRzKQpsaWJyYXJ5KHN5dXpoZXQpCmxpYnJhcnkod29yZGNsb3VkKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHRvcGljbW9kZWxzKQpgYGAKCmBgYHtyIGxvYWQgbGlicmFyaWVzLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQoKbGlicmFyeShEVCkKCmxpYnJhcnkoZ3JpZEV4dHJhKQoKYGBgCgojIyMjIFN0ZXAgMjogUHJvY2VzcyB0aGUgZGF0YQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIFRoaXMgZGF0YSBpcyBwcm9jZXNzZWQgZnJvbSBUZXh0X1ByZS1wcm9jZXNzaW5nIGZpbGUKaG1fZGF0YSA8LSByZWFkX2NzdigiLi4vZGF0YS9vdXRwdXQvcHJvY2Vzc2VkX21vbWVudHMuY3N2IikKCnVybGZpbGU8LSdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vcml0LXB1YmxpYy9IYXBweURCL21hc3Rlci9oYXBweWRiL2RhdGEvZGVtb2dyYXBoaWMuY3N2JwpkZW1vX2RhdGEgPC0gcmVhZF9jc3YodXJsZmlsZSkKCm5hbWVzKGhtX2RhdGEpCmBgYApgYGB7cn0KIyMgU2VsZWN0IHRoZSBkYXRhCmhhcHB5ZGIgPC0gaG1fZGF0YSAlPiUKICBpbm5lcl9qb2luKGRlbW9fZGF0YSwgYnkgPSAid2lkIikgJT4lCiAgc2VsZWN0KGdlbmRlciwgCiAgICAgICAgIHJlZmxlY3Rpb25fcGVyaW9kLAogICAgICAgICB0ZXh0KQoKIyBNZXJnZSB0aGUgdGV4dCBkYXRhIHdpdGggZGVtb2dyYXBoaWMgZGF0YSBpbnRvIGEgQ1NWIGZpbGUKIyB3cml0ZV9jc3YoaGFwcHlkYiwgIi4uL2RhdGEvb3V0cHV0L2hhcHB5ZGIuY3N2IikKIyBoYXBweWRiID0gcmVhZC5jc3YoIi4uL2RhdGEvb3V0cHV0L2hhcHB5ZGIuY3N2IikKCmBgYAoKCiMjIFBhcnQgMTogV2hhdCdzIHRoZSBkaWZmZXJlbmNlIG9mIHRoZSB3b3JkcyBpbiBlYWNoIGdlbmRlciBncm91cD8KSW4gb3JkZXIgdG8gYW5hbHl6ZSB0aGUgY29tcG9uZW50cyBvZiB0aGUgdGV4dCBpbiBlYWNoIGdyb3VwLCB0aGUgYmFycGxvdCBhbmQgd29yZGNsb3VkIGFyZSB1c2VkLgojIyMjIFN0ZXAgMSA6IEZpbHRlciBkYXRhCmBgYHtyLHdhcm5pbmc9RkFMU0V9CmZlbWFsZSA8LSBoYXBweWRiICU+JQogIGZpbHRlcihnZW5kZXIgPT0gJ2YnKQptYWxlIDwtIGhhcHB5ZGIgJT4lCiAgZmlsdGVyKGdlbmRlciA9PSAnbScpCgp1cmxmaWxlPC0naHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3JpdC1wdWJsaWMvSGFwcHlEQi9tYXN0ZXIvaGFwcHlkYi9kYXRhL3NlbnNlbGFiZWwuY3N2JwpzZW5zZV9kYXRhIDwtIHJlYWQuY3N2KHVybGZpbGUsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpgYGAKCiogUmVtb3ZlIFN0b3B3b3JkcwpgYGB7cn0KZGF0YSgic3RvcF93b3JkcyIpCgp3b3JkIDwtIGMoImhhcHB5IiwiYWdvIiwieWVzdGVyZGF5IiwibG90IiwidG9kYXkiLCJtb250aHMiLCJtb250aCIsCiAgICAgICAgICAgICAgICAgImhhcHBpZXIiLCJoYXBwaWVzdCIsImxhc3QiLCJ3ZWVrIiwicGFzdCIsImRheSIpCgpzdG9wX3dvcmRzIDwtIHN0b3Bfd29yZHMgJT4lCiAgYmluZF9yb3dzKG11dGF0ZSh0aWJibGUod29yZCksIGxleGljb24gPSAidXBkYXRlZCIpKQpgYGAKYGBge3J9CgojIGZlbWFsZXMnIGFuc3dlciB3b3JkIGNsZWFuaW5nCmZlbWFsZV90ZXh0IDwtIGZlbWFsZSR0ZXh0ICU+JSBhcy52ZWN0b3IoKSAgJT4lIAogIHRpYmJsZSh0ZXh0ID0gLikgJT4lIAogIHVubmVzdF90b2tlbnMod29yZCwgdGV4dCkgJT4lIAogIGFudGlfam9pbihzdG9wX3dvcmRzKQoKIyBtYWxlcycgYW5zd2VyIHdvcmQgY2xlYW5pbmcKbWFsZV90ZXh0IDwtIG1hbGUkdGV4dCAlPiUgYXMudmVjdG9yKCkgICU+JSAKICB0aWJibGUodGV4dCA9IC4pICU+JSAKICB1bm5lc3RfdG9rZW5zKHdvcmQsIHRleHQpICU+JSAKICBhbnRpX2pvaW4oc3RvcF93b3JkcykKYGBgCgojIyMjIFN0ZXAgMjogV29yZCBGcmVxdWVuY3kgCgoqIEVhY2ggZ2VuZGVyJ3Mgd29yZCBmcmVxdWVuY3kKYGBge3J9CmZyZXFfZiA8LSBmZW1hbGVfdGV4dCAlPiUgY291bnQod29yZCwgc29ydCA9IFRSVUUpICMgY291bnQgZnJlcXVlbmN5IGFuZCBzb3J0IGJ5IGRlc2NlbmRpbmcgb3JkZXIKZnJlcV9tIDwtIG1hbGVfdGV4dCAlPiUgY291bnQod29yZCwgc29ydCA9IFRSVUUpICMgY291bnQgZnJlcXVlbmN5IGFuZCBzb3J0IGJ5IGRlc2NlbmRpbmcgb3JkZXIKCiMgdmlzdWFsaXplIHRoZSBmcmVxdWVuY3kKZnJlcV9mICU+JQogIGZpbHRlcihuID4gMTUwMCkgJT4lCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUKICBnZ3Bsb3QoYWVzKHdvcmQsIG4pKSArCiAgZ2VvbV9jb2woZmlsbCA9ICJwaW5rIikgKwogIHhsYWIoTlVMTCkgKwogIGdndGl0bGUoIkZlbWFsZSB3b3JkIGZyZXF1ZW5jeSIpKwogIGNvb3JkX2ZsaXAoKQoKZnJlcV9tICU+JQogIGZpbHRlcihuID4gMTUwMCkgJT4lCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUKICBnZ3Bsb3QoYWVzKHdvcmQsIG4pKSArCiAgZ2VvbV9jb2woZmlsbD0gInNreWJsdWUiKSArCiAgeGxhYihOVUxMKSArCiAgZ2d0aXRsZSgiTWFsZSB3b3JkIGZyZXF1ZW5jeSIpKwogIGNvb3JkX2ZsaXAoKQpgYGAKCiogQ29tYmluYXRpb24gb2YgZ2VuZGVyIHdvcmQgZnJlcXVlbmN5CmBgYHtyfQojIGpvaW4gZWFjaCBnZW5kZXIncyB3b3JkIGZyZXF1ZW5jeSAKZnJlcXVlbmN5IDwtIGJpbmRfcm93cyhtdXRhdGUoZnJlcV9mLCBnZW5kZXIgPSAiRmVtYWxlIiksCiAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGZyZXFfbSwgZ2VuZGVyID0gIk1hbGUiKSkgJT4lCiAgIG11dGF0ZSh3b3JkID0gc3RyX2V4dHJhY3Qod29yZCwgIlthLXonXSsiKSkgJT4lCiAgIGNvdW50KGdlbmRlciwgd29yZCkgJT4lCiAgIGdyb3VwX2J5KGdlbmRlcikgJT4lCiAgIG11dGF0ZShwcm9wb3J0aW9uID0gbiAvIHN1bShuKSkgJT4lCiAgIHNlbGVjdCgtbikgJT4lICAjIGRlbGV0ZSBuIHZhcgogICBzcHJlYWQoZ2VuZGVyLCBwcm9wb3J0aW9uKSAlPiUgICMgd29yZCBmZW1hbGUgbWFsZSBhcyBjb2x1bW5zCiAgIGdhdGhlcihnZW5kZXIsIHByb3BvcnRpb24sIGBNYWxlYCkgJT4lIGRyb3BfbmEoKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoZnJlcXVlbmN5LCBhZXMoeCA9IHByb3BvcnRpb24sIHkgPSBgRmVtYWxlYCwgY29sb3IgPSBhYnMoYEZlbWFsZWAgLSBwcm9wb3J0aW9uKSkpICsKICBnZW9tX2FibGluZShjb2xvciA9ICJncmF5NDAiLCBsdHkgPSAyKSArCiAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjEsIHNpemUgPSAyLjUsIHdpZHRoID0gMC4zLCBoZWlnaHQgPSAwLjMpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gd29yZCksIGNoZWNrX292ZXJsYXAgPSBUUlVFLCB2anVzdCA9IDEuNSkgKwogIHNjYWxlX3hfbG9nMTAobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoKSkgKwogIHNjYWxlX3lfbG9nMTAobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoKSkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxpbWl0cyA9IGMoMCwgMC4wMDEpLCBsb3cgPSAiZGFya3NsYXRlZ3JheTQiLCBoaWdoID0gImdyYXk3NSIpICsKICBmYWNldF93cmFwKH5nZW5kZXIsIG5jb2wgPSAyKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwogIGxhYnMoeSA9ICJGZW1hbGUiLCB4ID0gTlVMTCkKYGBgCldvcmRzIHRoYXQgYXJlIGNsb3NlIHRvIHRoZSBsaW5lIGluIHRoZXNlIHBsb3RzIGhhdmUgc2ltaWxhciBmcmVxdWVuY2llcyBpbiBib3RoIHNldHMgb2YgdGV4dHMsIHdoaWNoIG1lYW5zIHRoZXJlIGlzIGh1Z2Ugc2ltaWxhcml0eSBiZXR3ZWVuIGZlbWFsZXMnIHJlc3BvbnNlIGFuZCBtYWxlcycgcmVzcG9uc2UKCiogQ29tYmluZSB3aXRoIHBvc2l0aW9uCmBgYHtyfQojIGNvbWJpbmUgd2l0aCBwb3NpdGlvbiAKcG9zIDwtIHNlbnNlX2RhdGEgJT4lCiAgc2VsZWN0KGxvd2VyY2FzZUxlbW1hLCBQT1MpICU+JSAKICByZW5hbWUod29yZCA9IGxvd2VyY2FzZUxlbW1hKSAgJT4lIAogIHVuaXF1ZSgpCgpwb3NfZiA8LSBmcmVxX2YgJT4lIGlubmVyX2pvaW4ocG9zKSAlPiUgCiAgZ3JvdXBfYnkoUE9TKSAlPiUgCiAgc3VtbWFyaXNlKG4gPSBzdW0obikpICU+JSAKICBtdXRhdGUocHJvcG9ydGlvbiA9IG4gL3N1bShuKSkKCnBvc19tICA8LSBmcmVxX20gJT4lIGlubmVyX2pvaW4ocG9zKSAgJT4lIAogIGdyb3VwX2J5KFBPUykgJT4lIAogIHN1bW1hcmlzZShuPSBzdW0obikpICU+JSAKICBtdXRhdGUocHJvcG9ydGlvbiA9IG4gL3N1bShuKSkKYGBgCgpgYGB7cn0KcG9zX2YgJT4lCiAgbXV0YXRlKFBPUyA9IHJlb3JkZXIoUE9TLCBwcm9wb3J0aW9uKSkgJT4lCiAgZ2dwbG90KGFlcyhQT1MsIHByb3BvcnRpb24pKSArCiAgZ2VvbV9jb2woZmlsbCA9ICJwaW5rIikgKwogIHhsYWIoTlVMTCkgKwogIGdndGl0bGUoIkZlbWFsZSBQYXJ0IG9mIFNwZWVjaCBQcm9wb3J0aW9uIikrCiAgY29vcmRfZmxpcCgpCgpwb3NfbSAlPiUKICBtdXRhdGUoUE9TID0gcmVvcmRlcihQT1MsIHByb3BvcnRpb24pKSAlPiUKICBnZ3Bsb3QoYWVzKFBPUywgcHJvcG9ydGlvbikpICsKICBnZW9tX2NvbChmaWxsID0gInNreWJsdWUiKSArCiAgeGxhYihOVUxMKSArCiAgZ2d0aXRsZSgiTWFsZSBQYXJ0IG9mIFNwZWVjaCBQcm9wb3J0aW9uIikrCiAgY29vcmRfZmxpcCgpCmBgYAoKCgoqIFdvcmRDbG91ZCBvZiB0ZXh0IHdvcmQKYGBge3J9CiMjIyBHZW5lcmFsIFdvcmQgQ2xvdWQKCiMgcGFsYXR0ZQpjb2xvclZlY19mID0gcmVwKGMoJ3JlZCcsICdsaWdodHBpbmsnKSwgbGVuZ3RoLm91dD1ucm93KGZyZXFfZikpCgpmcmVxX2YgJT4lIHdpdGgod29yZGNsb3VkKHdvcmQsIG4sIG1heC53b3JkcyA9IDEwMCwgY29sb3JzID1jb2xvclZlY19mKSkKCiMgcGFsYXR0ZQpjb2xvclZlY19tID0gcmVwKGMoJ2JsdWUnLCAnc2t5Ymx1ZScpLCBsZW5ndGgub3V0PW5yb3coZnJlcV9tKSkKCmZyZXFfbSAlPiUgd2l0aCh3b3JkY2xvdWQod29yZCwgbiwgbWF4LndvcmRzID0gMTAwLCBjb2xvcnMgPWNvbG9yVmVjX20pKQpgYGAKCiMjIyMgU3VtbWFyeQpUaGUgYmFycGxvdHMgc2hvdyB0aGF0IGJvdGggbWFsZSBhbmQgZmVtYWxlIGxpa2UgdXNlIG5vdW5zLCB2ZXJicyBhbmQgYWRqcyB0byBleHByZXNzIHRoZSBoYXBweSBtb21lbnRzLiBUaGUgdG9wIDEwIHdvcmRzIG9mIGZyZXF1ZW5jeSBpbiBlYWNoIGdyb3VwcyBhbHNvIHN1cHBvcnQgdGhlIG5vdGF0aW9uLiBXb21lbiBoYXZlIDggbm91bnMgYW5kIDIgdmVyYnMgYW5kIG1hbiBoYXZlIDcgbm91bnMsIDIgdmVyYnMgYW5kIDEgYWR2ZXJiKGZpbmFsbHkpLgoKSW4gdGhlIGJhcnBsb3QgYW5kIHdvcmRjbG91ZCBncmFwaHMgb2YgYm90aCBmZW1hbGUgYW5kIG1hbGUsIHdlIGNhbiBmaW5kIHRoYXQgYm90aCB3b21lbiBhbmQgbWVuIGFyZSBlbmpveWVkIHRoZSBoYXBweSBtb21lbnRzIHdpdGggdGhlaXIgZnJpZW5kcy4gQnV0IHdvbWVuIHRlbmQgdG8gYmUgbW9yZSBib25kIHdpdGggcGVvcGxlIGFyb3VuZCB0aGVtIGZvciB0aGUgd29yZHMgbGlrZSBodXNiYW5kLCBkYXVnaHRlciwgc29uLCBmYW1pbHkgY29tZSB1cCBtb3JlIGZyZXF1ZW50bHkgdGhhbiBtZW4ncy4gCgoKIyMgUGFydCAyOiBXaGF0J3MgdGhlIGRpZmZlcmVuY2Ugb2YgdGhlIHBlcmlvZHMgaW4gZWFjaCBnZW5kZXIgZ3JvdXA/CgpGb3IgdGhlIGluZm9tYXRpb24gb2YgdGhlIGRpZmZlcmVuY2UgaW4gdGhlIG51bWJlcnMgYW5kIGNvbnRlbnRzIG9mIHBlcmlvZHMgaW4gZWFjaCBnZW5kZXIgZ3JvdXAsIEknbSBnb25uYSB1c2UgdGhlIG51bWJlciBjb3VudCwgd29yZCBjbG91ZCBhbmQga3MtdGVzdC4KCiMjIyMgU3RlcCAxLiBOdW1iZXJzIG9mIHJlZmxlY3Rpb24KYGBge3J9CmdncGxvdChoYXBweWRiLGFlcyh4ID0gaGFwcHlkYiRnZW5kZXIsZmlsbCA9IGhhcHB5ZGIkcmVmbGVjdGlvbl9wZXJpb2QpKSsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikgKwogIGxhYnModGl0bGUgPSAnUmVmbGVjdGlvbiBQZXJpb2Qgb2YgRGlmZmVyZW50IEdlbmRlcicsIHggPSAnR2VuZGVyJykKYGBgCgojIyMjIFN0ZXAgMi4gRmlsdGVyaW5nCmBgYHtyfQpmMjRoIDwtIGZlbWFsZSAlPiUgZmlsdGVyKHJlZmxlY3Rpb25fcGVyaW9kID09ICIyNGgiKSAKZjNtIDwtIGZlbWFsZSAlPiUgZmlsdGVyKHJlZmxlY3Rpb25fcGVyaW9kID09ICIzbSIpCm0yNGggPC0gbWFsZSAlPiUgZmlsdGVyKHJlZmxlY3Rpb25fcGVyaW9kID09ICIyNGgiKSAKbTNtIDwtIG1hbGUgJT4lIGZpbHRlcihyZWZsZWN0aW9uX3BlcmlvZCA9PSAiM20iKQoKZnJlcV9mMjRoIDwtIGYyNGgkdGV4dCAlPiUgYXMudmVjdG9yKCkgICU+JQogIHRpYmJsZSh0ZXh0ID0gLikgJT4lCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCB0ZXh0KSAlPiUKICBhbnRpX2pvaW4oc3RvcF93b3JkcykgJT4lIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKQoKZnJlcV9mM20gPC0gZjNtJHRleHQgJT4lIGFzLnZlY3RvcigpICAlPiUKICB0aWJibGUodGV4dCA9IC4pICU+JQogIHVubmVzdF90b2tlbnMod29yZCwgdGV4dCkgJT4lCiAgYW50aV9qb2luKHN0b3Bfd29yZHMpICU+JSBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkKCmZyZXFfbTI0aCA8LSBtMjRoJHRleHQgJT4lIGFzLnZlY3RvcigpICAlPiUKICB0aWJibGUodGV4dCA9IC4pICU+JQogIHVubmVzdF90b2tlbnMod29yZCwgdGV4dCkgJT4lCiAgYW50aV9qb2luKHN0b3Bfd29yZHMpICU+JSBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkKCmZyZXFfbTNtIDwtIG0zbSR0ZXh0ICU+JSBhcy52ZWN0b3IoKSAgJT4lCiAgdGliYmxlKHRleHQgPSAuKSAlPiUKICB1bm5lc3RfdG9rZW5zKHdvcmQsIHRleHQpICU+JQogIGFudGlfam9pbihzdG9wX3dvcmRzKSAlPiUgY291bnQod29yZCwgc29ydCA9IFRSVUUpCgpgYGAKCiMjIyMgU3RlcCAzLiBQZXJpb2QgZGlmZmVyZW5jZSB3aXRoaW4gZ2VuZGVyIGdyb3VwCgoqIFByZXByb2Nlc3NpbmcKYGBge3J9CnBvc19mMjRoIDwtIGZyZXFfZjI0aCAlPiUgaW5uZXJfam9pbihwb3MpICU+JSAKICBncm91cF9ieShQT1MpICU+JSAKICBzdW1tYXJpc2UobiA9IHN1bShuKSkgJT4lIAogIG11dGF0ZShwcm9wb3J0aW9uID0gbiAvc3VtKG4pKQoKcG9zX2YzbSA8LSBmcmVxX2YzbSAlPiUgaW5uZXJfam9pbihwb3MpICU+JSAKICBncm91cF9ieShQT1MpICU+JSAKICBzdW1tYXJpc2UobiA9IHN1bShuKSkgJT4lIAogIG11dGF0ZShwcm9wb3J0aW9uID0gbiAvc3VtKG4pKQoKcGVyaW9kX2YgPC0gYmluZF9yb3dzKG11dGF0ZShwb3NfZjI0aCwgdGltZSA9ICIyNGgiKSwKICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUocG9zX2YzbSwgdGltZSA9ICIzbSIpKQoKcG9zX20yNGggPC0gZnJlcV9tMjRoICU+JSBpbm5lcl9qb2luKHBvcykgJT4lIAogIGdyb3VwX2J5KFBPUykgJT4lIAogIHN1bW1hcmlzZShuID0gc3VtKG4pKSAlPiUgCiAgbXV0YXRlKHByb3BvcnRpb24gPSBuIC9zdW0obikpCgpwb3NfbTNtIDwtIGZyZXFfbTNtICU+JSBpbm5lcl9qb2luKHBvcykgJT4lIAogIGdyb3VwX2J5KFBPUykgJT4lIAogIHN1bW1hcmlzZShuID0gc3VtKG4pKSAlPiUgCiAgbXV0YXRlKHByb3BvcnRpb24gPSBuIC9zdW0obikpCgpwZXJpb2RfbSA8LSBiaW5kX3Jvd3MobXV0YXRlKHBvc19tMjRoLCB0aW1lID0gIjI0aCIpLAogICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShwb3NfbTNtLCB0aW1lID0gIjNtIikpCgpwZXJpb2RfZiAlPiUKICBncm91cF9ieSh0aW1lKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKFBPUyA9IHJlb3JkZXIoUE9TLCBuKSkgJT4lCiAgZ2dwbG90KGFlcyhQT1MsIG4sIGZpbGwgPSB0aW1lKSkgKwogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsKICBmYWNldF93cmFwKH50aW1lLHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgbGFicyh5ID0gIkNvbnRyaWJ1dGlvbiB0byBQYXJ0IE9mIFNwZWVjaCIsCiAgICAgICB4ID0gTlVMTCkgKwogIGNvb3JkX2ZsaXAoKQoKcGVyaW9kX20gJT4lCiAgZ3JvdXBfYnkodGltZSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShQT1MgPSByZW9yZGVyKFBPUywgbikpICU+JQogIGdncGxvdChhZXMoUE9TLCBuLCBmaWxsID0gdGltZSkpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCh+dGltZSxzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnMoeSA9ICJDb250cmlidXRpb24gdG8gUGFydCBPZiBTcGVlY2giLAogICAgICAgeCA9IE5VTEwpICsKICBjb29yZF9mbGlwKCkKCmBgYAoKKiBXb3JkIENsb3VkCmBgYHtyfQp3b3JkX2YgPC0gYmluZF9yb3dzKG11dGF0ZShmcmVxX2YyNGgsIHRpbWUgPSAiMjRoIiksCiAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGZyZXFfZjNtLCB0aW1lID0gIjNtIikpCgp3b3JkX20gPC0gYmluZF9yb3dzKG11dGF0ZShmcmVxX20yNGgsIHRpbWUgPSAiMjRoIiksCiAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGZyZXFfbTNtLCB0aW1lID0gIjNtIikpCndvcmRfZiAlPiUKICBhY2FzdCh3b3JkIH4gdGltZSwgdmFsdWUudmFyID0gIm4iLCBmaWxsID0gMCkgJT4lCiAgY29tcGFyaXNvbi5jbG91ZChjb2xvcnMgPSBjKCJncmV5MjAiLCAicGluayIpLAogICAgICAgICAgICAgICAgICAgbWF4LndvcmRzID0gMTAwKQoKd29yZF9tICU+JQogIGFjYXN0KHdvcmQgfiB0aW1lLCB2YWx1ZS52YXIgPSAibiIsIGZpbGwgPSAwKSAlPiUKICBjb21wYXJpc29uLmNsb3VkKGNvbG9ycyA9IGMoImdyZXkyMCIsICJza3libHVlIiksCiAgICAgICAgICAgICAgICAgICBtYXgud29yZHMgPSAxMDApCmBgYAoKKiBLUyB0ZXN0CmBgYHtyfQprcy50ZXN0KHBvc19mMjRoJHByb3BvcnRpb24sIHBvc19mM20kcHJvcG9ydGlvbikKa3MudGVzdChwb3NfbTI0aCRwcm9wb3J0aW9uLCBwb3NfbTNtJHByb3BvcnRpb24pCmBgYAoKVGhlcmUgaXMgbm8gZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBwYXJ0IG9mIHNwZWVjaCBjaG9zZW4gaW4gdGhlIDMgbW9udGggb3IgMjQgaG91ciB3aXRoaW4gZWFjaCBnZW5kZXIgZ3JvdXAuCgojIyMjIFN0ZXAgNC4gUGVyaW9kIGRpZmZlcmVuY2UgYmV0d2VlbiBnZW5kZXIgZ3JvdXAKCiogUHJlcHJvY2Vzc2luZwpgYGB7ciwgd2FybmluZz1GQUxTRX0KaDI0IDwtIGJpbmRfcm93cyhtdXRhdGUocG9zX2YyNGgsIGdlbmRlciA9ICJmZW1hbGUiKSwKICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUocG9zX20yNGgsIGdlbmRlciA9ICJtYWxlIikpCm0zIDwtIGJpbmRfcm93cyhtdXRhdGUocG9zX2YzbSwgZ2VuZGVyID0gImZlbWFsZSIpLAogICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShwb3NfbTNtLCBnZW5kZXIgPSAibWFsZSIpKQoKaDI0ICU+JQogIGdyb3VwX2J5KGdlbmRlcikgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShQT1MgPSByZW9yZGVyKFBPUywgbikpICU+JQogIGdncGxvdChhZXMoUE9TLCBuLCBmaWxsID0gZ2VuZGVyKSkgKwogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsKICBmYWNldF93cmFwKH5nZW5kZXIsc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHkgPSAiQ29udHJpYnV0aW9uIHRvIFBhcnQgT2YgU3BlZWNoIiwKICAgICAgIHggPSBOVUxMLCB0aXRsZSA9ICIyNCBob3VyIikgKwogIGNvb3JkX2ZsaXAoKQoKbTMgJT4lCiAgZ3JvdXBfYnkoZ2VuZGVyKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKFBPUyA9IHJlb3JkZXIoUE9TLCBuKSkgJT4lCiAgZ2dwbG90KGFlcyhQT1MsIG4sIGZpbGwgPSBnZW5kZXIpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGZhY2V0X3dyYXAofmdlbmRlcixzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnMoeSA9ICJDb250cmlidXRpb24gdG8gUGFydCBPZiBTcGVlY2giLAogICAgICAgeCA9IE5VTEwgLCB0aXRsZSA9ICIzIG1vbnRoIikgKwogIGNvb3JkX2ZsaXAoKQoKYGBgCgoqIFdvcmQgQ2xvdWQKYGBge3J9CndvcmRfMjRoIDwtIGJpbmRfcm93cyhtdXRhdGUoZnJlcV9mMjRoLCBnZW5kZXIgPSAiZmVtYWxlIiksCiAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGZyZXFfbTI0aCwgZ2VuZGVyID0gIm1hbGUiKSkKCndvcmRfM20gPC0gYmluZF9yb3dzKG11dGF0ZShmcmVxX2YzbSwgZ2VuZGVyID0gImZlbWFsZSIpLAogICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShmcmVxX20zbSwgZ2VuZGVyID0gIm1hbGUiKSkKCndvcmRfMjRoICU+JQogIGFjYXN0KHdvcmQgfiBnZW5kZXIsIHZhbHVlLnZhciA9ICJuIiwgZmlsbCA9IDEpICU+JQogIGNvbXBhcmlzb24uY2xvdWQoY29sb3JzID0gYygicGluayIsICJza3libHVlIiksCiAgICAgICAgICAgICAgICAgICBtYXgud29yZHMgPSAxMDApCgp3b3JkXzNtICU+JQogIGFjYXN0KHdvcmQgfiBnZW5kZXIsIHZhbHVlLnZhciA9ICJuIiwgZmlsbCA9IDApICU+JQogIGNvbXBhcmlzb24uY2xvdWQoY29sb3JzID0gYygicGluayIsICJza3libHVlIiksCiAgICAgICAgICAgICAgICAgICBtYXgud29yZHMgPSAxMDApCgpgYGAKCiogS1MgdGVzdApgYGB7cn0KI3VzZSB0aGUga3MudGVzdAprcy50ZXN0KHBvc19mMjRoJHByb3BvcnRpb24scG9zX20yNGgkcHJvcG9ydGlvbik7a3MudGVzdChwb3NfZjNtJHByb3BvcnRpb24scG9zX20zbSRwcm9wb3J0aW9uKQpgYGAKCmBgYHtyfQojIyMjIFN0ZXAgNS4gVG9waWMgTW9kZWxpbmcKYGBgCgoKCiMjIyMgU3VtbWFyeSAKRm9yIGJvdGggZmVtYWxlIGFuZCBtYWxlLCB0aGVyZSBpcyBubyBkaWZmZXJlbmNlIGluIHRoZSB0b3RhbCBudW1iZXIgb2YgdGhlIHJlZmxlY3Rpb24gcGVyaW9kLiBCdXQgd2l0aCB0aGUgY29udGVudCBvZiBlYWNoIHBlcmlvZCwgZmVtYWxlIGFuZCBtYWxlIHNob3cgZGlmZmVyZW50bHkuCgpTaW5jZSB0aGUgcC12YWx1ZXMgb2YgS29sbW9nb3Jvdi1TbWlybm92IHRlc3QgYXJlIHZlcnkgY2xvc2UgdG8gMSwgdGhlIG51bGwgaHlwb3RoZXNpcyBjYW5ub3QgYmUgcmVqZWN0ZWQgYXQgMC4wMSBzaWduaWZpY2FuY2Ugd2hpY2ggbWVhbnMgdGhlcmUgaXMgbm8gc3RhdGlzdGljYWxseSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIFBPUyBvZiAyNCBob3VycyBhbmQgdGhhdCBvZiAzIG1vbnRocyBpbiBlYWNoIGdlbmRlciBncm91cC4KCkFmdGVyIHJlbW92aW5nIHRoZSBtb3N0IGZyZXF1ZW50bHkgdXNlZCB3b3JkcyBpbiBlYWNoIGdyb3VwLCB0aGUgcmVzdWx0cyBzaG93IHRoYXQgaW4gMjQtaG91cidzIG1lbW9yeSwgd29tZW4gaGF2ZSBtb3JlICdmbGVldGluZycgd29yZHMgLSB3b3JkcyBkZXNjcmliaW5nIG1vdmVtZW50LCBzdWNoIGFzIHdhdGNoZWQsIGZlZWwsIGVuam95LCBlY3QuIEluIDMtbW9udGgncyBtZW1vcnksIHdvbWVuIGhhdmUgbW9yZSBub3VucyBkZXNjcmliaW5nIHRoZSBwZXJzb24gdGhleSBzaGFyZWQgdGhlIGhhcHB5IG1vbWVudHMgd2l0aC4gVGhpcyBpcyBjb21wYXRpYmxlIHdpdGggdGhlIG1lbW9yeSBsb3NzLiBCdXQgZm9jdXNpbmcgb24gbWVuJ3Mgd29yZHMgaW4gZGlmZmVyZW50IHJlZmxlY3Rpb24gcGVyaW9kLCB0aGUgUE9TIG9mIHRoZSB3b3JkcyBzZWVtIHJlbWFpbi4KCgojIyBQYXJ0IDM6IFNlbnRpbWVudCBBbmFseXNpcwoKIyMjIyBTdGVwIDEuIGRhdGEgcHJvY2VzcwpgYGB7cn0KIyBvYnRhaW5lZCBzZW50aW1lbnQKYmluZyA9IGdldF9zZW50aW1lbnRzKCJiaW5nIikKCmZlbWFsZV9zZW50aW1lbnQgPC0gZmVtYWxlX3RleHQgJT4lIGlubmVyX2pvaW4oYmluZykgJT4lCiAgY291bnQod29yZCwgc2VudGltZW50LCBzb3J0ID0gVFJVRSkgJT4lCiAgdW5ncm91cCgpCgptYWxlX3NlbnRpbWVudCA8LSBtYWxlX3RleHQgJT4lIGlubmVyX2pvaW4oYmluZykgJT4lCiAgY291bnQod29yZCwgc2VudGltZW50LCBzb3J0ID0gVFJVRSkgJT4lCiAgdW5ncm91cCgpCgpgYGAKCiMjIyMgU3RlcCAyLiBiYXIgcGxvdApgYGB7cn0KZmVtYWxlX3NlbnRpbWVudCAlPiUKICBncm91cF9ieShzZW50aW1lbnQpICU+JQogIHRvcF9uKDEwKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUKICBnZ3Bsb3QoYWVzKHdvcmQsIG4sIGZpbGwgPSBzZW50aW1lbnQpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGZhY2V0X3dyYXAofnNlbnRpbWVudCwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHkgPSAiQ29udHJpYnV0aW9uIHRvIHNlbnRpbWVudCIsCiAgICAgICB4ID0gTlVMTCkgKwogIGNvb3JkX2ZsaXAoKQoKCm1hbGVfc2VudGltZW50ICU+JQogIGdyb3VwX2J5KHNlbnRpbWVudCkgJT4lCiAgdG9wX24oMTApICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUod29yZCA9IHJlb3JkZXIod29yZCwgbikpICU+JQogIGdncGxvdChhZXMod29yZCwgbiwgZmlsbCA9IHNlbnRpbWVudCkpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCh+c2VudGltZW50LCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnMoeSA9ICJDb250cmlidXRpb24gdG8gc2VudGltZW50IiwKICAgICAgIHggPSBOVUxMKSArCiAgY29vcmRfZmxpcCgpCmBgYApUaGUgdG9wIDEwIHdvcmRzIGluIHBvc2l0aXZlIGFuZCBuZWdhdGl2ZSBhc3BlY3QgZG9uJ3QgZGlmZmVyIGZyb20gZWFjaCBnZW5kZXIsIGp1c3QgdGhlIG9yZGVyIGNoYW5nZWQuCgojIyMjIFN0ZXAgM3MuIHdvcmQgY2xvdWQKYGBge3J9CmZlbWFsZV90ZXh0ICU+JQogIGlubmVyX2pvaW4oYmluZykgJT4lCiAgY291bnQod29yZCwgc2VudGltZW50LCBzb3J0ID0gVFJVRSkgJT4lCiAgYWNhc3Qod29yZCB+IHNlbnRpbWVudCwgdmFsdWUudmFyID0gIm4iLCBmaWxsID0gMCkgJT4lCiAgY29tcGFyaXNvbi5jbG91ZChjb2xvcnMgPSBjKCJncmV5MjAiLCAicGluayIpLAogICAgICAgICAgICAgICAgICAgbWF4LndvcmRzID0gMTAwKQoKCm1hbGVfdGV4dCAlPiUKICBpbm5lcl9qb2luKGJpbmcpICU+JQogIGNvdW50KHdvcmQsIHNlbnRpbWVudCwgc29ydCA9IFRSVUUpICU+JQogIGFjYXN0KHdvcmQgfiBzZW50aW1lbnQsIHZhbHVlLnZhciA9ICJuIiwgZmlsbCA9IDApICU+JQogIGNvbXBhcmlzb24uY2xvdWQoY29sb3JzID0gYygiZ3JheTIwIiwgInNreWJsdWUiKSwKICAgICAgICAgICAgICAgICAgIG1heC53b3JkcyA9IDEwMCkKYGBgCgojIyMjIFN0ZXAgNC4gS1MgdGVzdApIZXJlIHdlIHVzZSB0aGUgbnJjIHNlbnRpbWVudApgYGB7cn0KbnJjID0gZ2V0X3NlbnRpbWVudHMoIm5yYyIpCgpucmNfZiA8LSAgZmVtYWxlX3RleHQgJT4lCiAgaW5uZXJfam9pbihucmMpICU+JQogIGNvdW50KHdvcmQsc2VudGltZW50KSAlPiUKICBzcHJlYWQoc2VudGltZW50LCBuLCBmaWxsID0gMCkgJT4lCiAgc2VsZWN0KC13b3JkKSAlPiUgCiAgYXMubWF0cml4KCkgJT4lIAogIGFwcGx5KDIsc3VtKQoKbnJjX20gPC0gbWFsZV90ZXh0ICU+JQogIGlubmVyX2pvaW4obnJjKSAlPiUKICBjb3VudCh3b3JkLHNlbnRpbWVudCkgJT4lCiAgc3ByZWFkKHNlbnRpbWVudCwgbiwgZmlsbCA9IDApICU+JQogIHNlbGVjdCgtd29yZCkgJT4lIAogIGFzLm1hdHJpeCgpICU+JSAKICBhcHBseSgyLHN1bSkKCiNrcy50ZXN0IG9mIHNlbnRpbWVudCB2YWx1ZXMgb2YgZWFjaCBncm91cAprcy50ZXN0KG5yY19mLCBucmNfbSkKYGBgCgojIyMjIFN1bW1hcnkKQm90aCBmZW1hbGUgYW5kIG1hbGUgdXNlIG1vcmUgcG9zaXRpdmUgd29yZHMgdGhhbiBuZWdhdGl2ZSB3b3JkcyB0byBleHByZXNzIHRoZWlyIGhhcHB5IG1vbWVudHMuIEZvciB0aGUgc2Vuc2Ugb2Ygd29yZHMsIHRoZSB3b3JkcyB3aGljaCBzaG93IGpveSBhbmQgYW50aWNpcGF0aW9uIGFyZSBtb3JlIGxpa2VseSB1c2VkIGZvciBoYXBweSBtb21lbnRzLiBUaGUgaGlzdG9ncmFtIHNob3dzIGJvdGggbWVhbiBvZiB0aGUgc2VudGltZW50IHZhbHVlcyBhcmUgY29uY2VybnRyYXRlZCBvbiAwLiBVbmRlciB0aGUga3MudGVzdCwgdGhlcmUgaXMgbm8gc2lnbmlmaWNhbnRseSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHNlbnNlIHVzZWQgYnkgd29tZW4gYW5kIHRoYXQgYnkgbWFuLiAKCiMjIFBhcnQgNDogQ29uY2x1c2lvbgpGcm9tIHRoZSBhbmFseXNpcyBhYm92ZSwgd2UgY2FuIGZpcnN0bHkga25vdyB0aGF0IHRoZSBoYXBweSBtb21lbnRzIGFyZSBtb3N0bHkgcG9zdGl2ZSB3aGljaCBpcyBjb25maXJtZWQgd2l0aCB0aGUgbmFtZSBvZiB0aGUgcmVzZWFyY2ggJ0hhcHB5IE1vbWVudHMnLiBCb3RoIHdvbWVuIGFuZCBtZW4gdXNlZCBub3VucywgdmVyYnMgYW5kIGFkamVjdGl2ZXMgdG8gZXhwcmVzcyB0aGVpciBoYXBweSBtb21lbnRzLiBCZXNpZGVzLCB3b21lbiBsaWtlIHRvIHJlbWVtYmVyIHRoZSBwZW9wbGUgd2hvIHNwZW50IHRoZSBoYXBweSBtb21lbnRzIHdpdGggdGhlbSBidXQgbWVuIGRvbid0IHNob3cgdGhlIHRlbmRlbmN5LgoKVGhlcmUgaXMgbm8gc3RhdGlzdGljYWxseSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG51bWJlcnMgb2YgaGFwcHkgbW9tZW50cyBvZiBkaWZmZXJlbnQgcGVyaW9kIGluIGVhY2ggZ2VuZGVyIGdyb3VwLkJ1dCB0aGUgY29udGVudCBvZiB0aGUgd29yZCB1c2VkIGJ5IGZlbWFsZXMgYW5kIG1hbGVzIHNob3cgZGlmZmVyZW5jZS4gV29tZW4gdGVuZHMgdG8gdXNlIHZlcmJzIG9yIGFkamVjdGl2ZXMgdG8gZGVzY3JpYmUgdGhlaXIgaGFwcHkgbW9tZW50IGluIHNob3J0LXRlcm0gbWVtb3JpZXMsIG1vcmUgbm91bnMgZm9yIGRpc2NyaXB0aW9uIGluIGxvbmdlci10ZXJtIG1lbW9yaWVzIHdoaWxlIG1lbiBkb24ndCBzaG93IHRoZSBzYW1lIHRlbmRlbmN5LgoKCg==